#include "ring_buffer.h"


/* Private macro -------------------------------------------------------------------------------------------*/
#define IS_BUFFER_EMPTY(Read, Write)              (Write == Read)
#define IS_BUFFER_FULL(Read, Write, Size)         ((Write + 1) == Size ? (0 == Read) : ((Write + 1) == Read))

/* Global functions ----------------------------------------------------------------------------------------*/
/** @defgroup RING_BUFFER_Exported_Functions Ring Buffer exported functions
  * @{
  */
/*********************************************************************************************************//**
  * @brief  Buffer initialization.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @param  puMemory: Memory allocate by application
  * @param  uSize: Memory Size
  * @retval None
  ***********************************************************************************************************/
void Buffer_Init(Buffer_TypeDef *pBuffer, INT8U *puMemory, INT32U uSize)
{
  pBuffer->uRead = 0;
  pBuffer->uWrite = 0;
  pBuffer->puMemory = puMemory;
  pBuffer->uSize = uSize;

  return;
}

/*********************************************************************************************************//**
  * @brief  Read byte from buffer.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @param  puData: Pointer of returned data
  * @retval uResult: 1 for read success, 0 for no DATA
  ***********************************************************************************************************/
INT32U Buffer_ReadByte(Buffer_TypeDef *pBuffer, INT8U *puData)
{
  INT32U uResult = 0;
  if (!IS_BUFFER_EMPTY(pBuffer->uRead, pBuffer->uWrite))
  {
    *puData = pBuffer->puMemory[pBuffer->uRead];

    pBuffer->uRead++;

    if (pBuffer->uRead == pBuffer->uSize)
    {
      pBuffer->uRead = 0;
    }

    uResult = 1;
  }

  return uResult;
}

/*********************************************************************************************************//**
  * @brief  Write byte to buffer.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @param  uData: Data to write
  * @retval uResult: 1 for write success, 0 for buffer full
  ***********************************************************************************************************/
INT32U Buffer_WriteByte(Buffer_TypeDef *pBuffer, INT8U uData)
{
  INT32U uResult = 0;
  INT32U uDataLength;

  if (!IS_BUFFER_FULL(pBuffer->uRead, pBuffer->uWrite, pBuffer->uSize))
  {
    uDataLength = pBuffer->uWrite;
    pBuffer->puMemory[uDataLength] = uData;

    pBuffer->uWrite++;

    if (pBuffer->uWrite == pBuffer->uSize)
    {
      pBuffer->uWrite = 0;
    }
    uResult = 1;
  }
  return uResult;
}

/*********************************************************************************************************//**
  * @brief  Read buffer.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @param  puData: Pointer of dada buffer for read
  * @param  uLength: Read length
  * @retval uCount: Data length of read operation
  ***********************************************************************************************************/
INT32U Buffer_Read(Buffer_TypeDef *pBuffer, INT8U *puData, INT32U uLength)
{
  INT32U uCount;
  INT32U uResult;
  for (uCount = 0; uCount < uLength; uCount++)
  {
    uResult = Buffer_ReadByte(pBuffer, (INT8U *)(puData + uCount));
    if (!uResult)
    {
      break;
    }
  }

  return uCount;
}

/*********************************************************************************************************//**
  * @brief  Write Buffer.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @param  puData: Pointer of dada buffer for write
  * @param  uLength: Write length
  * @retval uCount: Data length of write operation
  ***********************************************************************************************************/
INT32U Buffer_Write(Buffer_TypeDef *pBuffer, INT8U *puData, INT32U uLength)
{
  INT32U uCount = 0;
  INT32U uResult;
  for (uCount = 0; uCount < uLength; uCount++)
  {
    uResult = Buffer_WriteByte(pBuffer, *(INT8U *)(puData + uCount));
    if (!uResult)
    {
      break;
    }
  }

  return uCount;
}

/*********************************************************************************************************//**
  * @brief  Check if buffer is empty.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @retval 1 for buffer is empty, 0 for buffer is not empty
  ***********************************************************************************************************/
INT32U Buffer_isEmpty(Buffer_TypeDef *pBuffer)
{
  return(IS_BUFFER_EMPTY(pBuffer->uRead, pBuffer->uWrite));
}

/*********************************************************************************************************//**
  * @brief  Check if buffer is full.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @retval 1 for buffer is full, 0 for buffer is not full
  ***********************************************************************************************************/
INT32U Buffer_isFull(Buffer_TypeDef *pBuffer)
{
  return(IS_BUFFER_FULL(pBuffer->uRead, pBuffer->uWrite, pBuffer->uSize));
}

/*********************************************************************************************************//**
  * @brief  Get buffer length.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @retval length
  ***********************************************************************************************************/
INT32U Buffer_GetLength(Buffer_TypeDef *pBuffer)
{
  if (pBuffer->uWrite >= pBuffer->uRead)
  {
    return (pBuffer->uWrite - pBuffer->uRead);
  }
  else
  {
    return (pBuffer->uSize - pBuffer->uRead + pBuffer->uWrite);
  }
}

/*********************************************************************************************************//**
  * @brief  Discard Buffer data.
  * @param  pBuffer: Pointer of Buffer_TypeDef
  * @retval None
  ***********************************************************************************************************/
void Buffer_Discard(Buffer_TypeDef *pBuffer)
{
  pBuffer->uRead = pBuffer->uWrite = 0;

  return;
}


